// Math
// (c) jimon game studio

#ifndef JEH_JEMATH
#define JEH_JEMATH

#include "jeTypes.h"
#include <math.h>

namespace je
{
	//! Pi constant
	const f32 jePi = 3.14159265359f;

	//! Pi 64 constant
	const f64 jePi64 = 3.1415926535897932384626433832795028841971693993751;

	//! Deg To Rad
	const f32 jeDegToRad = jePi / 180.0f;

	//! Rad To Deg
	const f32 jeRadToDeg = 180.0f / jePi;

	//! Rounding Error
	const f32 jeRoundingError32 = 0.000001f;

	//! Cos Function
	inline f32 jeCos(f32 Angle)
	{
		return cosf(Angle);
	}

	//! Sin Function
	inline f32 jeSin(f32 Angle)
	{
		return sinf(Angle);
	}

	//! Sin Cos Function
	inline void jeSinCos(f32 Angle,f32 & SinValue,f32 & CosValue)
	{
		#ifdef JE_MSVC
			__asm
			{
				fld Angle;
				fsincos;
				mov eax,[CosValue];
				fstp [eax];
				mov eax,[SinValue];
				fstp [eax];
			}
		#else
			SinValue = jeSin(Angle);
			CosValue = jeCos(Angle);
		#endif
	}

	//! Sqr f32
	inline f32 jeSqr(f32 Value)
	{
		return sqrtf(Value);
	}

	//! Inv Sqr f32
	inline f32 jeInvSqr(f32 Value)
	{
		#if defined(JE_MSVC) && defined(JE_ENABLE_SSE2)
			__asm
			{
				movss	xmm0, Value
				rsqrtss	xmm0, xmm0
				movss	Value, xmm0
			}
			return Value;
		#else
			return 1.0f / sqrtf(Value);
		#endif
	}

	//! Return max value from two
	template<class T>
	inline const T & jeMax(const T & a,const T & b)
	{
		return a < b ? b : a;
	}

	//! Return max value from three
	template<class T>
	inline const T & jeMax(const T & a,const T & b,const T & c)
	{
		return a < b ? jeMax(b, c) : jeMax(a, c);
	}

	//! Return min value from two
	template<class T>
	inline const T & jeMin(const T & a,const T & b)
	{
		return a < b ? a : b;
	}

	//! Return min value from three
	template<class T>
	inline const T & jeMin(const T & a,const T & b,const T & c)
	{
		return a < b ? jeMin(a, c) : jeMin(b, c);
	}

	//! Return value within defined boundaries
	template<class T>
	inline const T & jeClamp(const T & v,const T & min,const T & max)
	{
		return jeMin(jeMax(v,min),max);
	}

	//! Return ceil
	inline f32 jeCeil(const f32 & v)
	{
		return ceil(v);
	}

	//! Return floor
	inline f32 jeFloor(const f32 & v)
	{
		return floor(v);
	}

	#define JE_GET_BIT(__var,__num) (( __var >> __num)&1)
	#define JE_SET_BIT_1(__var,__num) __var = __var | ( 1 << __num )
	#define JE_SET_BIT_0(__var,__num) __var = __var & ~( 1 << __num )
	#define JE_SET_BIT(__var,__num,__val) if(__val){ __var = __var | ( 1 << __num ); }else{ __var = __var & ~( 1 << __num );}
}

#endif
